/**
 * 声音播放控制
 * ibio-develop
 * 2009-3-1 18:21
 */
package com.ibio8.media.sound {
	import com.ibio8.media.sound.events.SoundManagerEvent;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.media.Sound;
	import flash.media.SoundChannel;
	import flash.media.SoundLoaderContext;
	import flash.media.SoundTransform;
	import flash.net.URLRequest;
	import flash.utils.setTimeout;
	import flash.utils.clearTimeout;
	/**
	 * 声音播放控制。
	 * 
	 * <p>
	 * 声音播放控制，将 Flash API 归类整理，使得更容易被使用。和
	 * com.ibio8.media.sound.events.SoundManagerEvent 配合使用。
	 * </p>
	 * 
	 * @see com.ibio8.media.sound.events.SoundManagerEvent	SoundManagerEvent
	 */
	public class SoundManager extends EventDispatcher {
		/** @private **/
		protected var m_currentSound:Sound;
		/** @private **/
		protected var m_soundChannel:SoundChannel;
		/** @private **/
		protected var m_soundTransform:SoundTransform;
		/** @private **/
		protected var m_bufferTimer:uint;
		/** @private **/
		protected var m_isPlaying:Boolean = false;
		/** @private **/
		protected var m_lastKnownPosition:Number = 0;
		/** @private **/
		protected var m_loadPosition:Number = 0;
		/** @private **/
		protected var m_volume:Number = 0;
		
		/**
		 * 构造函数
		 */
		public function SoundManager() {
			m_soundTransform = new SoundTransform();
		}
		
		/**
		 * 加载音乐
		 * @param	url			音乐 url
		 * @param	autoPlay	是否自动播放
		 * @param	bufferTime	加载缓冲时间，默认为 500 毫秒
		 */
		public function load(url:String, autoPlay:Boolean = true, bufferTime:uint = 500):void {
			close();
			m_lastKnownPosition = 0;
			m_isPlaying = false;
			//
			m_currentSound = new Sound();
			m_currentSound.addEventListener(Event.COMPLETE, onSoundLoadedHandler);
			m_currentSound.addEventListener(IOErrorEvent.IO_ERROR, onSoundLoadedErrorHandler);
			m_currentSound.addEventListener(ProgressEvent.PROGRESS, onSoundLoadingHandler);
			//
			var context:SoundLoaderContext = new SoundLoaderContext(bufferTime);
			m_currentSound.load(new URLRequest(url), context);
			//是否是自动播放
			if(autoPlay){
				startBufferTimer(bufferTime);
			}
		}
		
		/**
		 * 播放
		 */
		public function play():void {
			if (m_isPlaying) {
				return;
			}
			//如果仍在缓冲，则等待缓冲
			if (isBuffering) {
				startBufferTimer();
			}else {
				try {
					m_soundChannel = m_currentSound.play(m_lastKnownPosition, 0, m_soundTransform);
					m_soundChannel.addEventListener(Event.SOUND_COMPLETE, onSoundCompletedHandler);
					m_isPlaying = true;
					dispatchEvent(new SoundManagerEvent(SoundManagerEvent.PLAYING));
				}catch (e:Error) {
					trace("SoundManager::play->" + e.message);
				}
			}
		}
		
		/**
		 * 暂停
		 */
		public function pause():void {
			if (!m_isPlaying) {
				return;
			}
			try {
				m_lastKnownPosition = m_soundChannel.position;
				m_soundChannel.stop();
				m_isPlaying = false;
			}catch(e:Error){
				trace("SoundManager::pause->" + e.message);
			}
		}
		
		/**
		 * 停止
		 */
		public function stop():void {
			try {
				m_soundChannel.stop();
				clearTimeout(m_bufferTimer);
				m_lastKnownPosition = 0;
				m_isPlaying = false;
			}catch(e:Error){
				trace("SoundManager::stop->" + e.message);
			}
		}
		
		/**
		 * 关闭声音流
		 */
		public function close():void{
			if (!m_currentSound) {
				return;
			}
			stop();
			try {
				m_currentSound.close();
				clearTimeout(m_bufferTimer);
				m_currentSound.removeEventListener(Event.COMPLETE, onSoundLoadedHandler);
				m_currentSound.removeEventListener(IOErrorEvent.IO_ERROR, onSoundLoadedErrorHandler);
				m_currentSound.removeEventListener(ProgressEvent.PROGRESS, onSoundLoadingHandler);
				m_soundChannel.removeEventListener(Event.SOUND_COMPLETE, onSoundCompletedHandler);
			}catch(e:Error){
				trace("SoundManager::close->" + e.message);
			}
			m_currentSound = null;
			m_soundChannel = null;
		}
		
		/**
		 * 静音
		 */
		public function set mute(value:Boolean):void {
			if (value) {
				if (volume == 0) {
					return;
				}
				//记录当前的声音大小
				m_volume = volume;
				try {
					m_soundTransform.volume = 0;
					m_soundChannel.soundTransform = m_soundTransform;
				}catch(e:Error){
					trace("SoundManager::set volume->" + e.message);
				}
			}else {
				if (volume != 0) {
					return;
				}
				volume  = m_volume;
			}
		}
		
		public function get mute():Boolean {
			return (volume == 0);
		}
		
		/**
		 * 设置当前音量，0--1
		 */
		public function set volume(value:Number):void {
			try {
				m_soundTransform.volume = value;
				m_soundChannel.soundTransform = m_soundTransform;
				m_volume = value;
			}catch(e:Error){
				trace("SoundManager::set volume->" + e.message);
			}
		}
		
		public function get volume():Number{
			var r:Number = 1;
			try {
				r = m_soundTransform.volume;
			}catch(e:Error){
				trace("SoundManager::get volume->", e.message);
			}
			return r;
		}
		
		/**
		 * 设置当前播放的播放时长（毫秒）
		 */
		public function set position(value:Number):void {
			var currentIsPlaying:Boolean = m_isPlaying;
			stop();
			try {
				m_soundChannel.removeEventListener(Event.SOUND_COMPLETE, onSoundCompletedHandler);
			}catch (e:Error) {
				//
			}
			m_lastKnownPosition = value;
			//如果当前是播放状态，则继续播放
			if (currentIsPlaying) {
				play();
			}
		}
		
		/**
		 * 返回当前播放的时间(毫秒)
		 */
		public function get position():Number {
			var p:Number = 0;
			try {
				p = m_soundChannel.position;
			}catch(e:Error){
				//trace("SoundManager::get position->", e.message);
			}
			return p;
		}
		
		/**
		 * 返回总的播放时长(毫秒)
		 */
		public function get length():Number {
			var l:Number = 0;
			try {
				/**
				 * 注：当歌曲没有加载完成的时候这里是大概的时长
				 * 总时长 = 当前已经下载的时长 / 当前加载的百分比
				 */
				l = m_currentSound.length / m_loadPosition;
			}catch(e:Error){
				//trace("SoundManager::get length->", e.message);
			}
			return l;
		}
		
		/**
		 * 返回当前播放进度(0--1)
		 */
		public function get playProgress():Number {
			var p:Number = 0;
			try {
				p = position / length;
			}catch(e:Error){
				//trace("SoundManager::get playProgress->", e.message);
			}
			return p;
		}
		
		/**
		 * 返回加载进度(0--1)
		 */
		public function get loadProgress():Number {
			return m_loadPosition;
		}
		
		/**
		 * 是否正在播放
		 */
		public function get isPlaying():Boolean {
			return m_isPlaying;
		}
		
		/**
		 * 是否正在缓冲
		 */
		public function get isBuffering():Boolean {
			var b:Boolean = false;
			try {
				b = m_currentSound.isBuffering;
			}catch (e:Error) {
				//trace("SoundManager::isBuffering->", e.message);
			}
			return b;
		}
		
		/** @private **/
		protected function startBufferTimer(delay:Number = 0):void {
			clearTimeout(m_bufferTimer);
			m_bufferTimer = setTimeout(onBufferTimeout, delay);
		}
		
		/** @private **/
		protected function onBufferTimeout():void {
			//如果当期仍然在buffering，每隔 0.1 秒在检查一次，直到缓冲结束
			if(isBuffering){
				startBufferTimer(100);
			}else {
				play();
			}
		}
		
		/** @private **/
		//整首歌全部下载完毕
		protected function onSoundLoadedHandler(e:Event):void {
			dispatchEvent(new SoundManagerEvent(SoundManagerEvent.LOAD_COMPLETE));
		}
		
		/** @private **/
		protected function onSoundLoadedErrorHandler(e:Event):void{
			close();
			dispatchEvent(new SoundManagerEvent(SoundManagerEvent.LOAD_ERROR));
		}
		
		/** @private **/
		protected function onSoundLoadingHandler(e:ProgressEvent):void{
			m_loadPosition = e.bytesLoaded / e.bytesTotal;
		}
		
		/** @private **/
		//播放完毕
		protected function onSoundCompletedHandler(e:Event):void{
			close();
			dispatchEvent(new SoundManagerEvent(SoundManagerEvent.PLAY_COMPLETE));
		}
	}
}